﻿using System;
using Csla;
using System.ComponentModel.DataAnnotations;
using BizControl.DalLinq;
using BizControl.Library.BusinessObjects.People;
using BizControl.Library.BusinessObjects.Activities;
using Csla.Rules.CommonRules;
using Csla.Data;
using System.Data.Linq;
using BizControl.Library.Security;
using BizControl.Resources;

namespace BizControl.Library.BusinessObjects.Marks
{
  [Serializable()]
  public enum DetailTypes : int
  {
    User = 0,
    Quality = 1,
    Privilege = 2,
    StartDate = 3,
    EndDate = 4
  }

  [Serializable()]
  public class MarkDetailBO : BusinessBase<MarkDetailBO>
  {
    #region Business Methods

    private static readonly PropertyInfo<Guid> MarkDetailIdProperty = RegisterProperty<Guid>(c => c.MarkDetailId);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MarkDetailIdRequiredPropertyError")]
    public Guid MarkDetailId
    {
      get { return GetProperty(MarkDetailIdProperty); }
      private set { SetProperty<Guid>(MarkDetailIdProperty, value); }
    }

    private static readonly PropertyInfo<MarkInfo> MarkProperty = RegisterProperty<MarkInfo>(c => c.Mark);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MarkDetailMarkRequiredPropertyError")]
    MarkInfo Mark
    {
      get { return GetProperty(MarkProperty); }
      set { SetProperty(MarkProperty, value); }
    }
    
    private static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MarkDetailNameRequiredPropertyError")]
    [StringLength(50, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MarkDetailNameLengthPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"MarkDetailNameProperty")]
    public string Name
    {
      get { return GetProperty(NameProperty); }
      set { SetProperty(NameProperty, value); }
    }

    private static readonly PropertyInfo<string> ValueProperty = RegisterProperty<string>(c => c.Value);
    [Display(ResourceType = typeof(PropertiesNames), Name = @"MarkDetailValueProperty")]
    public string Value
    {
      get { return GetProperty(ValueProperty); }
      set { SetProperty(ValueProperty, value); }
    }

    private static readonly PropertyInfo<DetailTypes> DetailTypeProperty = RegisterProperty<DetailTypes>(c => c.DetailType, null, DetailTypes.User);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MarkDetailTypeRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"MarkDetailTypeProperty")]
    public int DetailType
    {
      get { return GetPropertyConvert<DetailTypes, int>(DetailTypeProperty); }
      internal set { SetPropertyConvert<DetailTypes, int>(DetailTypeProperty, value); }
    }

    #region Common properties

    private static readonly PropertyInfo<bool> IsDeletedFieldProperty = RegisterProperty<bool>(c => c.IsDeletedField, null, false);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"IsDeletedRequiredError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"IsDeletedFieldProperty")]
    public bool IsDeletedField
    {
      get { return GetProperty(IsDeletedFieldProperty); }
      private set { SetProperty(IsDeletedFieldProperty, value); }
    }

    private static readonly PropertyInfo<PersonInfo> CreatedByProperty = RegisterProperty<PersonInfo>(c => c.CreatedBy);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CreatedByRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CreatedByProperty")]
    public PersonInfo CreatedBy
    {
      get { return GetProperty(CreatedByProperty); }
      private set { SetProperty(CreatedByProperty, value); }
    }

    private static readonly PropertyInfo<DateTime> CreatedOnProperty = RegisterProperty<DateTime>(c => c.CreatedOn);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CreatedOnRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CreatedOnProperty")]
    public DateTime CreatedOn
    {
      get { return GetProperty(CreatedOnProperty); }
      private set { SetPropertyConvert(CreatedOnProperty, value); }
    }

    private static readonly PropertyInfo<DateTime> LastChangedProperty = RegisterProperty<DateTime>(c => c.LastChanged);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"LastChangedRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"LastChangedProperty")]
    public DateTime LastChanged
    {
      get { return GetProperty(LastChangedProperty); }
      private set { SetProperty(LastChangedProperty, value); }
    }

    private static readonly PropertyInfo<PersonInfo> LastChangedByProperty = RegisterProperty<PersonInfo>(c => c.LastChangedBy);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"LastChangedByRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"LastChangedByProperty")]
    public PersonInfo LastChangedBy
    {
      get { return GetProperty(LastChangedByProperty); }
      private set { SetProperty(LastChangedByProperty, value); }
    }

    private static readonly PropertyInfo<byte[]> TimeStampProperty = RegisterProperty<byte[]>(c => c.TimeStamp);
    private byte[] TimeStamp
    {
      get { return GetProperty(TimeStampProperty); }
      set { SetProperty(TimeStampProperty, value); }
    }

    #endregion

    internal void LoadData(MarkDetail markDetailDB)
    {
      if (markDetailDB == null) return;
      MarkDetailId = markDetailDB.MarkDetailId;
      Name = markDetailDB.Name;
      Value = markDetailDB.Value;
      DetailType = markDetailDB.DetailType ?? (int)DetailTypes.User;

      // Common properties
      CreatedBy = new PersonInfo(markDetailDB.CreatedByRef);
      LastChangedBy = new PersonInfo(markDetailDB.LastChangedByRef);

      CreatedOn = markDetailDB.CreatedOn;
      LastChanged = markDetailDB.LastChanged;

      IsDeletedField = markDetailDB.IsDeleted;
      TimeStamp = markDetailDB.TimeStamp.ToArray();
    }

    #endregion

    #region Business Rules

    protected override void AddBusinessRules()
    {
      base.AddBusinessRules();
    }

    #endregion

    #region  Data Access

    private void Child_Create(MarkInfo mark)
    {
      if (mark == null) throw new ArgumentNullException(ExceptionsMessages.MarkNullReference);
      var currentUser = SecurityChecks.GetCurrentUser();
      using (BypassPropertyChecks)
      {
        MarkDetailId = Guid.NewGuid();
        Mark = mark;
        CreatedBy = new PersonInfo(currentUser);
        LastChangedBy = new PersonInfo(currentUser);
        CreatedOn = DateTime.Now;
      }
      base.Child_Create();
    }

    private void Child_Fetch(MarkDetail data, MarkInfo mark)
    {
      if (mark == null) throw new ArgumentNullException(ExceptionsMessages.MarkNullReference);
      using (BypassPropertyChecks)
      {
        Mark = mark;
        LoadData(data);
      }
    }

    private void Child_Insert()
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        Binary lastTimeStamp = null;
        LastChanged = DateTime.Now;
        using (BypassPropertyChecks)
        {
          ctx.DataContext.AddMarkDetail(
            Mark == null || Mark.IsEmpty() ? (Guid?)null : Mark.Id,
            MarkDetailId,
            Name,
            Value,
            DetailType,
            IsDeletedField,
            CreatedBy == null || CreatedBy.IsEmpty() ? (Guid?)null : CreatedBy.Id,
            CreatedOn,
            LastChanged,
            LastChangedBy == null || LastChangedBy.IsEmpty() ? (Guid?)null : LastChangedBy.Id,
            ref lastTimeStamp);
          TimeStamp = lastTimeStamp.ToArray();
        }
      }
    }

    private void Child_Update()
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        if (IsSelfDirty)
        {
          Binary lastTimeStamp = null;
          LastChangedBy = new PersonInfo(SecurityChecks.GetCurrentUser());
          LastChanged = DateTime.Now;
          using (BypassPropertyChecks)
          {
            ctx.DataContext.UpdateMarkDetail(
              Mark == null || Mark.IsEmpty() ? (Guid?)null : Mark.Id,
              MarkDetailId,
              Name,
              Value,
              DetailType,
              IsDeletedField,
              LastChanged,
              LastChangedBy == null || LastChangedBy.IsEmpty() ? (Guid?)null : LastChangedBy.Id,
              TimeStamp,
              ref lastTimeStamp);
            TimeStamp = lastTimeStamp.ToArray();
          }
        }
      }
    }

    #endregion

    #region  Factory Methods

    internal static MarkDetailBO NewMarkDetail(MarkInfo mark)
    {
      return Csla.DataPortal.CreateChild<MarkDetailBO>(mark);
    }

    internal static MarkDetailBO GetMarkDetail(MarkDetail data, MarkInfo mark)
    {
      return Csla.DataPortal.FetchChild<MarkDetailBO>(data, mark);
    }

    private MarkDetailBO()
    { /* require use of factory methods */ }

    #endregion  
  }
}
